'====================================================================
' Represents the facade for the whole Chat functionality.
' Singleton.
' HiddenCarrier knows about and uses this class.
'====================================================================
Public NotInheritable Class Chat
	Implements IDisposable

	Public Event UserConnected(ByVal Sender As RemoteUser)
	Public Event UserDisconnected(ByVal Sender As RemoteUser)
	Public Event UserReceivedText(ByVal Sender As RemoteUser, ByVal Text As String)
	Public Event UserStatusChanged(ByVal Sender As RemoteUser)

	'====================================================================
	' 1. Server-functionality layer. Port listener.
	'====================================================================

	' Port listener that exists throughout the execution of the program.
	' Created and started in Chat.Start()
	Private WithEvents Listener As LocalPort

	'====================================================================
	' 2. Client-functionality layer. User list.
	'====================================================================

	' This user's contact list.
	Private WithEvents mUsers As UserList = New UserList()

	Public ReadOnly Property Users() As UserList
		Get
			Return mUsers
		End Get
	End Property

	'====================================================================
	' Initializing
	'====================================================================

	Private Shared ReadOnly mInstance As Chat = New Chat()

	Private Sub New()
		Users.Load()
	End Sub

	' Thread-safe Singleton instance
	Public Shared Function Instance() As Chat
		Return mInstance
	End Function

	Public Sub Start()
		Listener = New LocalPort()
		Users.Connect()
	End Sub

	'====================================================================
	' Terminating
	'====================================================================

	Protected Overrides Sub Finalize()
		MyBase.Finalize()
		Dispose()
	End Sub

	Public Sub Dispose() Implements System.IDisposable.Dispose
		If Not Listener Is Nothing Then
			Users.Disconnect()
			Listener.Dispose()
			Listener = Nothing
		End If
	End Sub

	'====================================================================
	' Established incoming connection.
	' Called from Listener object (Class LocalPort).
	'====================================================================

	Private Sub Listener_EstablishedConnection(ByVal Name As String, ByVal UserAddress As String, ByVal ExistingConnection As Agent.UserConnection) Handles Listener.EstablishedConnection
		Dim NewlyConnectedUser As RemoteUser = Users(Name)

		If Not NewlyConnectedUser Is Nothing Then
			NewlyConnectedUser.ConnectRespond(ExistingConnection)
		Else
			If MessageBox.Show("Would you like to add a new user " & Name & " to your contact list?", "New user requests connection", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
				Users.AddUserIncomingRequest(Name, UserAddress, ExistingConnection)
			End If
		End If
	End Sub

	'====================================================================
	' Pass on the events further along the chain of responsibility.
	'====================================================================

#Region " User list events "

	Private Sub OnUserConnected(ByVal Sender As Agent.RemoteUser) Handles mUsers.UserConnected
		RaiseEvent UserConnected(Sender)
	End Sub

	Private Sub OnUserDisconnected(ByVal Sender As Agent.RemoteUser) Handles mUsers.UserDisconnected
		RaiseEvent UserDisconnected(Sender)
	End Sub

	Private Sub OnUserReceivedText(ByVal Sender As Agent.RemoteUser, ByVal Text As String) Handles mUsers.UserReceivedText
		RaiseEvent UserReceivedText(Sender, Text)
	End Sub

	Private Sub OnUserStatusChanged(ByVal Sender As Agent.RemoteUser) Handles mUsers.UserStatusChanged
		RaiseEvent UserStatusChanged(Sender)
	End Sub

#End Region

End Class